package com.dnake.misc;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;

import com.dnake.v700.dxml;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;

public class SysWifi {
	public static final int SECURITY_NONE = 0;
	public static final int SECURITY_WEP = 1;
	public static final int SECURITY_PSK = 2;
	public static final int SECURITY_WPA2_PSK = 3;

	public static WifiManager mWifi;
	public static ConnectivityManager mConnect;

	public static int mEnabled = 0;
	public static int mMode = 1; //
	public static String mSSID = "SmartAP";
	public static String mPasswd = "";

	public static void load() {
		dxml p = new dxml();
		p.load("/dnake/cfg/sys_wifi.xml");
		mEnabled = p.getInt("/sys/enabled", 0);
		mMode = p.getInt("/sys/mode", 0);
		mSSID = p.getText("/sys/ssid", "SmartAP");
		mPasswd = p.getText("/sys/passwd", "12345678");

		if (mEnabled == 0)
			SysWifi.setEnabled(false);
	}

	public static void save() {
		dxml p = new dxml();
		p.setInt("/sys/enabled", mEnabled);
		p.setInt("/sys/mode", mMode);
		p.setText("/sys/ssid", mSSID);
		p.setText("/sys/passwd", mPasswd);
		p.save("/dnake/cfg/sys_wifi.xml");

		if (mEnabled == 0) {
			SysWifi.setEnabled(false);
		} else {
			Thread t = new Thread(new ProcessThread());
			t.start();
		}
	}

	private static long mTs = 0;
	public static void process() {
		if (mEnabled != 0 && !isConnected() && Math.abs(System.currentTimeMillis()-mTs) >= 2*60*1000) {
			mTs = System.currentTimeMillis();
			Thread t = new Thread(new ProcessThread());
			t.start();
		}
	}

	public static class ProcessThread implements Runnable {
		@Override
		public void run() {
			if (mEnabled == 0) {
				if (isEnabled())
					setEnabled(false);
				if (isWifiApEnabled())
					setWifiApEnabled(false);
			} else {
				if (mMode == 0) {
					if (!isEnabled())
						setEnabled(true);
					else {
						setEnabled(false);
						for (int i = 0; i < 50; i++) {
							if (mWifi.getWifiState() == WifiManager.WIFI_STATE_DISABLED)
								break;
							try {
								Thread.sleep(200);
							} catch (InterruptedException e) {
							}
						}
						setEnabled(true);
					}
					setWifiConfiguration(mSSID, mPasswd);
					mWifi.startScan();
				} else {
					if (!isWifiApEnabled())
						setWifiApEnabled(true);
					else {
						setWifiApEnabled(false);
						try {
							Thread.sleep(5*1000);
						} catch (InterruptedException e) {
						}
						setWifiApEnabled(true);
					}
					setWifiApConfiguration(mSSID, mPasswd);
				}
			}
		}
	}

	public static void start(Context ctx) {
		mWifi = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
		mConnect = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
		SysWifi.load();
	}

	public static Boolean isConnected() {
		if (mConnect != null) {
			NetworkInfo ni = mConnect.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
			if (ni != null)
				return ni.isAvailable();
		}
		return false;
	}

	public static void setEnabled(Boolean enabled) {
		if (mWifi != null) {
			if (enabled) {
				if (isWifiApEnabled())
					setWifiApEnabled(false);
				if (!mWifi.isWifiEnabled()) {
					mWifi.setWifiEnabled(true);
				}
			} else {
				if (mWifi.isWifiEnabled()) {
					mWifi.setWifiEnabled(false);
				}
			}
		}
	}

	public static Boolean isEnabled() {
		if (mWifi != null)
			return mWifi.isWifiEnabled();
		return false;
	}

	public static WifiConfiguration genWifiConfiguration(String ssid, String passwd, int security) {
		WifiConfiguration c = new WifiConfiguration();

		c.SSID = '"'+ssid+'"';
		c.hiddenSSID = true;

		switch (security) {
		case SECURITY_NONE:
			c.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
			break;

		case SECURITY_WEP:
			c.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
			c.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
			c.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
			if (passwd.length() > 0) {
				int length = passwd.length();
				if ((length == 10 || length == 26 || length == 58) && passwd.matches("[0-9A-Fa-f]*")) {
					c.wepKeys[0] = passwd;
				} else {
					c.wepKeys[0] = '"' + passwd + '"';
				}
			}
			break;

		case SECURITY_PSK:
			c.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
			c.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
			if (passwd.length() > 0) {
				if (passwd.matches("[0-9A-Fa-f]{64}")) {
					c.preSharedKey = passwd;
				} else {
					c.preSharedKey = '"' + passwd + '"';
				}
			}
			break;

		case SECURITY_WPA2_PSK:
			c.status = WifiConfiguration.Status.ENABLED;
			c.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
			c.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
			c.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
			c.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
			c.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
			c.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
			c.preSharedKey = '"' + passwd + '"';
			break;
		}
		return c;
	}

	public static void setWifiConfiguration(String ssid, String passwd) {
		for (int i = 0; i < 50; i++) {
			if (mWifi.getWifiState() == WifiManager.WIFI_STATE_ENABLED)
				break;
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
			}
		}
		if (mEnabled == 0 || mWifi.getWifiState() != WifiManager.WIFI_STATE_ENABLED)
			return;

		List<WifiConfiguration> w = mWifi.getConfiguredNetworks();
		if (w != null) {
			for (WifiConfiguration c : w) {
				System.err.println("####################BSSID: "+c.BSSID+" "+c.networkId);
				mWifi.removeNetwork(c.networkId);
			}
			try {
				Thread.sleep(1*1000);
			} catch (InterruptedException e) {
			}
		}

		WifiConfiguration wc = genWifiConfiguration(ssid, passwd, SECURITY_WPA2_PSK);
		setEnumField(wc, "DHCP", "ipAssignment"); // setEnumField(c, "STATIC", "ipAssignment");
		int id = mWifi.addNetwork(wc);
		mWifi.enableNetwork(id, false);
	}

	public static void setWifiApEnabled(boolean enabled) {
		if (enabled && mWifi.isWifiEnabled()) {
			mWifi.setWifiEnabled(false);
		}

		try {
			Method m = mWifi.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
			m.invoke(mWifi, null, enabled);
		} catch (Exception e) {
		}
	}

	public static void setWifiApConfiguration(String ssid, String passwd) {
		try {
			WifiConfiguration c = new WifiConfiguration();
			c.SSID = ssid;
			if (passwd != null && passwd.length() > 0) {
				c.preSharedKey = passwd;
				c.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
				c.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
			} else
				c.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
			Method m = mWifi.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
			m.invoke(mWifi, c);
		} catch (Exception e) {
		}
	}

	public static Boolean isWifiApEnabled() {
		Boolean result = false;
		try {
			Method m = mWifi.getClass().getMethod("isWifiApEnabled");
			result = (Boolean) m.invoke(mWifi);
		} catch (Exception e) {
		}
		return result;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void setEnumField(Object obj, String value, String name) {
		Field f;
		try {
			f = obj.getClass().getField(name);
			f.set(obj, Enum.valueOf((Class<Enum>) f.getType(), value));
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public static Object getField(Object obj, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
		Field f = obj.getClass().getField(name);
		Object out = f.get(obj);
		return out;
	}

	public static Object getDeclaredField(Object obj, String name) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
		Field f = obj.getClass().getDeclaredField(name);
		f.setAccessible(true);
		Object out = f.get(obj);
		return out;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void setIpAddress(InetAddress addr, int prefixLength, WifiConfiguration c) {
		Object linkProperties;
		try {
			linkProperties = getField(c, "linkProperties");
			Class<?> laClass = Class.forName("android.net.LinkAddress");
			Constructor<?> laConstructor = laClass.getConstructor(new Class[] { InetAddress.class, int.class });
			Object linkAddress = laConstructor.newInstance(addr, prefixLength);
			ArrayList mLinkAddresses = (ArrayList) getDeclaredField(linkProperties, "mLinkAddresses");
			mLinkAddresses.clear();
			mLinkAddresses.add(linkAddress);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
